package gas.backend;

import java.io.IOException;
import java.util.*;

import gas.backend.image.image;
import gas.backend.tac.*;

public class Interpreter {
	private IntermediateCodeReader iCodeReader;
	private StorageMap iSymbolTable;
	
	public Interpreter(Object ic) {
		iCodeReader = new IntermediateCodeReader(ic);
		iSymbolTable = new StorageMap();
	}
	
	public void run() throws IOException {
		ICTac current;
		while((current = iCodeReader.nextTac()) != null) {
			execute(current);
		}
	}
	
	private void execute(ICTac line) throws IOException {
		if (line.symbolList.size()==1 && line.symbolList.get(0).type==ICSymbolType.VAR) {
			
			System.out.println("var_"+line.symbolList.get(0).value+"="+iSymbolTable.get(line.symbolList.get(0).value));
		}
		else if (line.symbolList.size()==2 && line.symbolList.get(0).type==ICSymbolType.VAR) {
				iSymbolTable.put(line.symbolList.get(0).value, GetValue(line.symbolList.get(1)));
				System.out.println("var_"+line.symbolList.get(0).value+"="+iSymbolTable.get(line.symbolList.get(0).value));
		}
		else if (line.symbolList.size()==3 && line.symbolList.get(0).type==ICSymbolType.VAR &&
				line.symbolList.get(1).type==ICSymbolType.ARIT_OP) {
			if (line.symbolList.get(1).value.equals("-")) {
				iSymbolTable.put(line.symbolList.get(0).value, Negative(GetValue(line.symbolList.get(2))));					
			}
			System.out.println("var_"+line.symbolList.get(0).value+"="+iSymbolTable.get(line.symbolList.get(0).value));
		}
		else if (line.symbolList.size()==4 && line.symbolList.get(0).type==ICSymbolType.VAR) {
			iSymbolTable.put(line.symbolList.get(0).value, OperateValue(GetValue(line.symbolList.get(1)), GetValue(line.symbolList.get(3)), line.symbolList.get(2)));		
			System.out.println("var_"+line.symbolList.get(0).value+"="+iSymbolTable.get(line.symbolList.get(0).value));
		}
		else if (line.symbolList.size()==4 && line.symbolList.get(0).type==ICSymbolType.KEYWORD &&
				line.symbolList.get(0).value.equals("if") && line.symbolList.get(2).value.equals("goto")) {
			if (GetValue(line.symbolList.get(1)).equals(true)) {
				iCodeReader.count=Integer.parseInt(line.symbolList.get(3).value.toString());
			}
		}
		else if (line.symbolList.size()==3 && line.symbolList.get(0).type==ICSymbolType.VAR && 
				line.symbolList.get(1).type==ICSymbolType.TYPENAME && line.symbolList.get(2).type==ICSymbolType.FILEPATH) {
		    iSymbolTable.put(line.symbolList.get(0).value, LoadObject(line.symbolList.get(1).value, line.symbolList.get(2).value.toString()));
			System.out.println("var_"+line.symbolList.get(0).value+"="+iSymbolTable.get(line.symbolList.get(0).value));
		}
		else if (line.symbolList.size()==2 && line.symbolList.get(0).type==ICSymbolType.FILEPATH) {
			ObjectSavetoFile(iSymbolTable.get(line.symbolList.get(1).value), line.symbolList.get(0).value.toString());
		}
	}
	
	private void ObjectSavetoFile(Object x, String filename) throws IOException {
		if (x instanceof image) {
			((image) x).savetofile(filename);
		}
	}
	
	private Object LoadObject(Object x, String filename) throws IOException {
		if (x.equals("image")) {
			return new image(filename);
		}
		else {
			return null;
		}
	}
	
	private Object OperateValue(Object x, Object y, ICSymbol symbol) {
		if (symbol.type==ICSymbolType.ARIT_OP) {
			if (x instanceof Integer) {
				if (symbol.value.equals("+")) {
					return Integer.parseInt(x.toString())+Integer.parseInt(y.toString());
				}
				else if (symbol.value.equals("-")) {
					return Integer.parseInt(x.toString())-Integer.parseInt(y.toString());
				}
				else if (symbol.value.equals("*")) {
					return Integer.parseInt(x.toString())*Integer.parseInt(y.toString());
				}
				else if (symbol.value.equals("/")) {
					return Integer.parseInt(x.toString())/Integer.parseInt(y.toString());
				}
			}
		}
		else if (symbol.type==ICSymbolType.CMPR_OP) {
			if (x instanceof Integer) {
				if (symbol.value.equals(">")) {
					return (Integer.parseInt(x.toString())>Integer.parseInt(y.toString()));
				}
				if (symbol.value.equals("<")) {
					return (Integer.parseInt(x.toString())<Integer.parseInt(y.toString()));
				}
			}
		}		
		return x;
	}
	
	private Object GetValue(ICSymbol symbol) {
		if (symbol.type==ICSymbolType.NUM) {
			return symbol.value;
		}
		else if (symbol.type==ICSymbolType.VAR) {
			return iSymbolTable.get(symbol.value);
		}
		else {
			return null;
		}
	}
	
	private Object Negative(Object value) {
		if (value instanceof Integer) {
			return -Integer.parseInt(value.toString());
		}
		return value;
	}
	
}
